1 using UnityEngine;
2 using
System.Collections;
3
4
5 public
enum PickupCharacterState
6 {
7     Idle =
0,
8     Walking =
1,
9     Trotting =
2,
10     Running =
3,
11     Jumping =
4,
12 }

13
14 [RequireComponent(
typeof(CharacterController))]
15 public
class PickupController : MonoBehaviour, IPunObservable
16 {
17
18     
public AnimationClip idleAnimation;
19     
public AnimationClip walkAnimation;
20     
public AnimationClip runAnimation;
21     
public AnimationClip jumpPoseAnimation;
22
23     
public float walkMaxAnimationSpeed = 0.75f;
24     
public float trotMaxAnimationSpeed = 1.0f;
25     
public float runMaxAnimationSpeed = 1.0f;
26     
public float jumpAnimationSpeed = 1.15f;
27     
public float landAnimationSpeed = 1.0f;
28
29     
private Animation _animation;
30
31
32
33     
public PickupCharacterState _characterState;
34
35     
// The speed when walking
36     
public float walkSpeed = 2.0f;
37     
// after trotAfterSeconds of walking we trot with trotSpeed
38     
public float trotSpeed = 4.0f;
39     
// when pressing "Fire3" button (cmd) we start running
40     
public float runSpeed = 6.0f;
41
42     
public float inAirControlAcceleration = 3.0f;
43
44     
// How high do we jump when pressing jump and letting go immediately
45     
public float jumpHeight = 0.5f;
46
47     
// The gravity for the character
48     
public float gravity = 20.0f;
49     
// The gravity in controlled descent mode
50     
public float speedSmoothing = 10.0f;
51     
public float rotateSpeed = 500.0f;
52     
public float trotAfterSeconds = 3.0f;
53
54     
public bool canJump = false;
55
56     
private float jumpRepeatTime = 0.05f;
57     
private float jumpTimeout = 0.15f;
58     
private float groundedTimeout = 0.25f;
59
60     
// The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
61     
private float lockCameraTimer = 0.0f;
62
63     
// The current move direction in x-z
64     
private Vector3 moveDirection = Vector3.zero;
65     
// The current vertical speed
66     
private float verticalSpeed = 0.0f;
67     
// The current x-z move speed
68     
private float moveSpeed = 0.0f;
69
70     
// The last collision flags returned from controller.Move
71     
private CollisionFlags collisionFlags;
72
73     
// Are we jumping? (Initiated with jump button and not grounded yet)
74     
private bool jumping = false;
75     
private bool jumpingReachedApex = false;
76
77     
// Are we moving backwards (This locks the camera to not do a 180 degree spin)
78     
private bool movingBack = false;
79     
// Is the user pressing any keys?
80     
private bool isMoving = false;
81     
// When did the user start walking (Used for going into trot after a while)
82     
private float walkTimeStart = 0.0f;
83     
// Last time the jump button was clicked down
84     
private float lastJumpButtonTime = -10.0f;
85     
// Last time we performed a jump
86     
private float lastJumpTime = -1.0f;
87     
// the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
88     
//private float lastJumpStartHeight = 0.0f;
89     
private Vector3 inAirVelocity = Vector3.zero;
90
91     
private float lastGroundedTime = 0.0f;
92     Vector3 velocity = Vector3.zero;
93     
private Vector3 lastPos;
94     
private Vector3 remotePosition;
95
96     
public bool isControllable = false;
97     
public bool DoRotate = true;
98     
public float RemoteSmoothing = 5;
99     
public bool AssignAsTagObject = true;
100
101     
void Awake()
102     {
103         
// PUN: automatically determine isControllable, if this GO has a PhotonView
104         PhotonView pv =
this.gameObject.GetComponent<PhotonView>();
105         
if (pv != null)
106         {
107             isControllable = pv.isMine;
108
109             
// The pickup demo assigns this GameObject as the PhotonPlayer.TagObject. This way, we can access this character (controller, position, etc) easily
110             
if (this.AssignAsTagObject)
111             {
112                 pv.owner.TagObject =
this.gameObject;
113             }
114
115             
// please note: we change this setting on ANY PickupController if "DoRotate" is off. not only locally when it's "our" GameObject!
116             
if (pv.observed is Transform && !DoRotate)
117             {
118                 pv.onSerializeTransformOption = OnSerializeTransform.OnlyPosition;
119             }
120         }
121
122
123         moveDirection = transform.TransformDirection(Vector3.forward);
124
125         _animation = GetComponent<Animation>();
126         
if (!_animation)
127             Debug.Log(
"The character you would like to control doesn't have animations. Moving her might look weird.");
128
129         
if (!idleAnimation)
130         {
131             _animation =
null;
132             Debug.Log(
"No idle animation found. Turning off animations.");
133         }
134         
if (!walkAnimation)
135         {
136             _animation =
null;
137             Debug.Log(
"No walk animation found. Turning off animations.");
138         }
139         
if (!runAnimation)
140         {
141             _animation =
null;
142             Debug.Log(
"No run animation found. Turning off animations.");
143         }
144         
if (!jumpPoseAnimation && canJump)
145         {
146             _animation =
null;
147             Debug.Log(
"No jump animation found and the character has canJump enabled. Turning off animations.");
148         }
149     }
150
151     
void Update()
152     {
153         
if (isControllable)
154         {
155             
if (Input.GetButtonDown("Jump"))
156             {
157                 lastJumpButtonTime = Time.time;
158             }
159
160             UpdateSmoothedMovementDirection();
161
162             
// Apply gravity
163             
// - extra power jump modifies gravity
164             
// - controlledDescent mode modifies gravity
165             ApplyGravity();
166
167             
// Apply jumping logic
168             ApplyJumping();
169
170
171             
// Calculate actual motion
172             Vector3 movement = moveDirection * moveSpeed +
new Vector3(0, verticalSpeed, 0) + inAirVelocity;
173             movement *= Time.deltaTime;
174
175             
//Debug.Log(movement.x.ToString("0.000") + ":" + movement.z.ToString("0.000"));
176
177             
// Move the controller
178             CharacterController controller = GetComponent<CharacterController>();
179             collisionFlags = controller.Move(movement);
180
181         }
182
183         
// PUN: if a remote position is known, we smooth-move to it (being late(r) but smoother)
184         
if (this.remotePosition != Vector3.zero)
185         {
186             transform.position = Vector3.Lerp(transform.position,
this.remotePosition, Time.deltaTime * this.RemoteSmoothing);
187         }
188
189         velocity = (transform.position - lastPos)*
25;
190
191         
// ANIMATION sector
192         
if (_animation)
193         {
194             
if (_characterState == PickupCharacterState.Jumping)
195             {
196                 
if (!jumpingReachedApex)
197                 {
198                     _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;
199                     _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
200                     _animation.CrossFade(jumpPoseAnimation.name);
201                 }
202                 
else
203                 {
204                     _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed;
205                     _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
206                     _animation.CrossFade(jumpPoseAnimation.name);
207                 }
208             }
209             
else
210             {
211                 
if (_characterState == PickupCharacterState.Idle)
212                 {
213                     _animation.CrossFade(idleAnimation.name);
214                 }
215                 
else if (_characterState == PickupCharacterState.Running)
216                 {
217                     _animation[runAnimation.name].speed = runMaxAnimationSpeed;
218                     
if (this.isControllable)
219                     {
220                         _animation[runAnimation.name].speed = Mathf.Clamp(velocity.magnitude,
0.0f, runMaxAnimationSpeed);
221                     }
222                     _animation.CrossFade(runAnimation.name);
223                 }
224                 
else if (_characterState == PickupCharacterState.Trotting)
225                 {
226                     _animation[walkAnimation.name].speed = trotMaxAnimationSpeed;
227                     
if (this.isControllable)
228                     {
229                         _animation[walkAnimation.name].speed = Mathf.Clamp(velocity.magnitude,
0.0f, trotMaxAnimationSpeed);
230                     }
231                     _animation.CrossFade(walkAnimation.name);
232                 }
233                 
else if (_characterState == PickupCharacterState.Walking)
234                 {
235                     _animation[walkAnimation.name].speed = walkMaxAnimationSpeed;
236                     
if (this.isControllable)
237                     {
238                         _animation[walkAnimation.name].speed = Mathf.Clamp(velocity.magnitude,
0.0f, walkMaxAnimationSpeed);
239                     }
240                     _animation.CrossFade(walkAnimation.name);
241                 }
242                 
243                 
if (_characterState != PickupCharacterState.Running)
244                 {
245                     _animation[runAnimation.name].time =
0.0f;
246                 }
247             }
248         }
249         
// ANIMATION sector
250
251         
// Set rotation to the move direction
252         
if (IsGrounded())
253         {
254             
// a specialty of this controller: you can disable rotation!
255             
if (DoRotate)
256             {
257                 transform.rotation = Quaternion.LookRotation(moveDirection);
258             }
259         }
260         
else
261         {
262             
/* This causes choppy behaviour when colliding with SIDES
263              * Vector3 xzMove = velocity;
264             xzMove.y =
0;
265             
if (xzMove.sqrMagnitude > 0.001f)
266             {
267                 transform.rotation = Quaternion.LookRotation(xzMove);
268             }*/

269         }
270
271         
// We are in jump mode but just became grounded
272         
if (IsGrounded())
273         {
274             lastGroundedTime = Time.time;
275             inAirVelocity = Vector3.zero;
276             
if (jumping)
277             {
278                 jumping =
false;
279                 SendMessage(
"DidLand", SendMessageOptions.DontRequireReceiver);
280             }
281         }
282
283         lastPos = transform.position;
284     }
285
286     
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
287     {
288         
if (stream.isWriting)
289         {
290             stream.SendNext(
this.transform.position);
291             stream.SendNext((
byte)this._characterState);
292         }
293         
else
294         {
295             
bool initialRemotePosition = (remotePosition == Vector3.zero);
296             
297             remotePosition = (Vector3)stream.ReceiveNext();
298             
this._characterState = (PickupCharacterState)((byte)stream.ReceiveNext());
299
300             
if (initialRemotePosition)
301             {
302                 
// avoids lerping the character from "center" to the "current" position when this client joins
303                 
this.transform.position = remotePosition;
304             }
305         }
306     }
307
308     
void UpdateSmoothedMovementDirection()
309     {
310         Transform cameraTransform = Camera.main.transform;
311         
bool grounded = IsGrounded();
312
313         
// Forward vector relative to the camera along the x-z plane
314         Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
315         forward.y =
0;
316         forward = forward.normalized;
317
318         
// Right vector relative to the camera
319         
// Always orthogonal to the forward vector
320         Vector3 right =
new Vector3(forward.z, 0, -forward.x);
321
322         
float v = Input.GetAxisRaw("Vertical");
323         
float h = Input.GetAxisRaw("Horizontal");
324
325         
// Are we moving backwards or looking backwards
326         
if (v < -0.2f)
327             movingBack =
true;
328         
else
329             movingBack =
false;
330
331         
bool wasMoving = isMoving;
332         isMoving = Mathf.Abs(h) >
0.1f || Mathf.Abs(v) > 0.1f;
333
334         
// Target direction relative to the camera
335         Vector3 targetDirection = h * right + v * forward;
336         
// Debug.Log("targetDirection " + targetDirection);
337
338         
// Grounded controls
339         
if (grounded)
340         {
341             
// Lock camera for short period when transitioning moving & standing still
342             lockCameraTimer += Time.deltaTime;
343             
if (isMoving != wasMoving)
344                 lockCameraTimer =
0.0f;
345
346             
// We store speed and direction seperately,
347             
// so that when the character stands still we still have a valid forward direction
348             
// moveDirection is always normalized, and we only update it if there is user input.
349             
if (targetDirection != Vector3.zero)
350             {
351                 
// If we are really slow, just snap to the target direction
352                 
if (moveSpeed < walkSpeed * 0.9f && grounded)
353                 {
354                     moveDirection = targetDirection.normalized;
355                 }
356                 
// Otherwise smoothly turn towards it
357                 
else
358                 {
359                     moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime,
1000);
360
361                     moveDirection = moveDirection.normalized;
362                 }
363             }
364
365             
// Smooth the speed based on the current target direction
366             
float curSmooth = speedSmoothing * Time.deltaTime;
367
368             
// Choose target speed
369             
//* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
370             
float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f);
371
372             _characterState = PickupCharacterState.Idle;
373
374             // Pick speed modifier
375             
if ((Input.GetKey(KeyCode.LeftShift) | Input.GetKey(KeyCode.RightShift)) && isMoving)
376             {
377                 targetSpeed *= runSpeed;
378                 _characterState = PickupCharacterState.Running;
379             }
380             
else if (Time.time - trotAfterSeconds > walkTimeStart)
381             {
382                 targetSpeed *= trotSpeed;
383                 _characterState = PickupCharacterState.Trotting;
384             }
385             
else if (isMoving)
386             {
387                 targetSpeed *= walkSpeed;
388                 _characterState = PickupCharacterState.Walking;
389             }
390         
391             moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
392
393             // Reset walk time start
when we slow down
394             
if (moveSpeed < walkSpeed * 0.3f)
395                 walkTimeStart = Time.time;
396         }
397         // In air controls
398         
else
399         {
400             // Lock camera
while in air
401             
if (jumping)
402                 lockCameraTimer =
0.0f;
403
404             
if (isMoving)
405                 inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration;
406         }
407     }
408
409     
void ApplyJumping()
410     {
411         // Prevent jumping too fast after each other
412         
if (lastJumpTime + jumpRepeatTime > Time.time)
413             
return;
414
415         
if (IsGrounded())
416         {
417             // Jump
418             // - Only
when pressing the button down
419             // - With a timeout so you can press the button slightly before landing
420             
if (canJump && Time.time < lastJumpButtonTime + jumpTimeout)
421             {
422                 verticalSpeed = CalculateJumpVerticalSpeed(jumpHeight);
423                 SendMessage(
"DidJump", SendMessageOptions.DontRequireReceiver);
424             }
425         }
426     }
427
428     
void ApplyGravity()
429     {
430         
if (isControllable) // don't move player at all if not controllable.
431         {
432             // Apply gravity
433             //
bool jumpButton = Input.GetButton("Jump");
434             
435             // When we reach the apex of the jump we send
out a message
436             
if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0f)
437             {
438                 jumpingReachedApex =
true;
439                 SendMessage(
"DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
440             }
441
442             
if (IsGrounded())
443                 verticalSpeed =
0.0f;
444             
else
445                 verticalSpeed -= gravity * Time.deltaTime;
446         }
447     }
448
449     
float CalculateJumpVerticalSpeed(float targetJumpHeight)
450     {
451         // From the jump height and gravity we deduce the upwards speed
452         //
for the character to reach at the apex.
453         
return Mathf.Sqrt(2 * targetJumpHeight * gravity);
454     }
455
456     
void DidJump()
457     {
458         jumping =
true;
459         jumpingReachedApex =
false;
460         lastJumpTime = Time.time;
461         //lastJumpStartHeight = transform.position.y;
462         lastJumpButtonTime = -
10;
463
464         _characterState = PickupCharacterState.Jumping;
465     }
466
467     
void OnControllerColliderHit(ControllerColliderHit hit)
468     {
469         // Debug.DrawRay(hit.point, hit.normal);
470         
if (hit.moveDirection.y > 0.01f)
471             
return;
472     }
473
474     
public float GetSpeed()
475     {
476         
return moveSpeed;
477     }
478
479     
public bool IsJumping()
480     {
481         
return jumping;
482     }
483
484     
public bool IsGrounded()
485     {
486         
return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
487     }
488
489     
public Vector3 GetDirection()
490     {
491         
return moveDirection;
492     }
493
494     
public bool IsMovingBackwards()
495     {
496         
return movingBack;
497     }
498
499     
public float GetLockCameraTimer()
500     {
501         
return lockCameraTimer;
502     }
503
504     
public bool IsMoving()
505     {
506         
return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f;
507     }
508
509     
public bool HasJumpReachedApex()
510     {
511         
return jumpingReachedApex;
512     }
513
514     
public bool IsGroundedWithTimeout()
515     {
516         
return lastGroundedTime + groundedTimeout > Time.time;
517     }
518
519     
public void Reset()
520     {
521         gameObject.tag =
"Player";
522     }
523 }


The speed when walking

after trotAfterSeconds of walking we trot with trotSpeed

when pressing "Fire3" button (cmd) we start running

How high do we jump when pressing jump and letting go immediately

The gravity for the character

The gravity in controlled descent mode

The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.

The current move direction in x-z

The current vertical speed

The current x-z move speed

The last collision flags returned from controller.Move

Are we jumping? (Initiated with jump button and not grounded yet)

Are we moving backwards (This locks the camera to not do a 180 degree spin)

Is the user pressing any keys?

When did the user start walking (Used for going into trot after a while)

Last time the jump button was clicked down

Last time we performed a jump

the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)

private float lastJumpStartHeight = 0.0f;

PUN: automatically determine isControllable, if this GO has a PhotonView

The pickup demo assigns this GameObject as the PhotonPlayer.TagObject. This way, we can access this character (controller, position, etc) easily

please note: we change this setting on ANY PickupController if "DoRotate" is off. not only locally when it's "our" GameObject!

Apply gravity

- extra power jump modifies gravity

- controlledDescent mode modifies gravity

Apply jumping logic

Calculate actual motion

Debug.Log(movement.x.ToString("0.000") + ":" + movement.z.ToString("0.000"));

Move the controller

PUN: if a remote position is known, we smooth-move to it (being late(r) but smoother)

ANIMATION sector

ANIMATION sector

Set rotation to the move direction

a specialty of this controller: you can disable rotation!

We are in jump mode but just became grounded

avoids lerping the character from "center" to the "current" position when this client joins

Forward vector relative to the camera along the x-z plane

Right vector relative to the camera

Always orthogonal to the forward vector

Are we moving backwards or looking backwards

Target direction relative to the camera

Debug.Log("targetDirection " + targetDirection);

Grounded controls

Lock camera for short period when transitioning moving & standing still

We store speed and direction seperately,

so that when the character stands still we still have a valid forward direction

moveDirection is always normalized, and we only update it if there is user input.

If we are really slow, just snap to the target direction

Otherwise smoothly turn towards it

Smooth the speed based on the current target direction

Choose target speed

* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways

Pick speed modifier

Reset walk time start when we slow down

In air controls

Lock camera while in air

Prevent jumping too fast after each other

Jump

- Only when pressing the button down

- With a timeout so you can press the button slightly before landing

if (isControllable) don't move player at all if not controllable.

Apply gravity

bool jumpButton = Input.GetButton("Jump");

When we reach the apex of the jump we send out a message

From the jump height and gravity we deduce the upwards speed

for the character to reach at the apex.

lastJumpStartHeight = transform.position.y;

Debug.DrawRay(hit.point, hit.normal);




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.561 lượt xem

Gõ tìm kiếm nhanh...